package com.xqh.service.impl.ques;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.xqh.base.dao.CrudMapper;
import com.xqh.base.exception.ServiceException;
import com.xqh.base.service.impl.BaseCrudServiceImpl;
import com.xqh.base.util.excel.ExcelReader;
import com.xqh.base.util.id.IdWorker;
import com.xqh.base.util.word.SpecialCharUtils;
import com.xqh.dao.ques.QuestionTmpMapper;
import com.xqh.entity.ques.*;
import com.xqh.entity.ques.json.*;
import com.xqh.enums.QuesTypeEnum;
import com.xqh.service.ques.*;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 
 * @author leo
 * @date 2018-04-25 15:44:35
 * @version 1.0.0
 * @copyright www.vip-young.com
 */
@Service("questionTmpService")
public class QuestionTmpServiceImpl extends BaseCrudServiceImpl<QuestionTmp> implements QuestionTmpService {

    @Resource
    private QuestionTmpMapper questionTmpMapper;

    @Autowired
    private ImportRecordService recordService;

    @Autowired
    private QuesTypeService quesTypeService;

    @Autowired
    private VocabularyService vocabularyService;

    @Autowired
    private BookService bookService;

    @Autowired
    private BookUnitService bookUnitService;

    @Autowired
    private KnowledgePointService knowledgePointService;

    private static final String PREFIX_A="A.";

    private static final String PREFIX_B="B.";

    private static final String PREFIX_C="C.";

    private static final String PREFIX_D="D.";

    private static final String PREFIX_E="E.";

    private static final String PREFIX_F="F.";

    private static final String PREFIX_G="G.";

    private static final String PREFIX_H="H.";

    private static final String PREFIX_I="I.";

    @Override
    public CrudMapper init() {
        return questionTmpMapper;
    }

    @Override
    @Transactional
    public int saveData(QuestionTmp entity) throws ServiceException {
        Assert.notNull(entity, "参数不能为空");
        Assert.isTrue(StringUtils.hasText(entity.getImportCode()) &&
                StringUtils.hasText(entity.getQuesTypeCode()), "参数缺失");

        ImportRecord record = recordService.getByCode(entity.getImportCode());
        QuesType type = quesTypeService.getByLongCode(entity.getQuesTypeCode());//查询 题型相关数据

        List<QuestionTmp> tlist = parseExcelData(record.getFilePath(), type);

        /**
         * 处理课本 单元知识点
         */
        handleBookUnitKPs(tlist);

        if(QuesTypeEnum.VOCAB.getName().equals(type.getQuesType())){
            vocabQuesHandle(tlist);
        }else{
            //同步练习 类型题目
            syncQuesHandle(tlist, record);
        }

        questionTmpMapper.batchInsertQues(tlist);



        //TODO 词汇 或者 课文 等其他 特殊题型 需要特殊处理


        return -1;
    }


    /**
     * 处理词汇类型题目
     * @param tlist
     */
    private void vocabQuesHandle(List<QuestionTmp> tlist) {

        /**
         * 查询词汇信息
         */
        handleVocabulary(tlist);

        /**
         * 生成 词汇类 题目内容
         */
        createVocabQuesContent(tlist);


    }

    /**
     * 词汇类 题目
     * @param tlist
     */
    private void createVocabQuesContent(List<QuestionTmp> tlist) {
        for(QuestionTmp tmp:tlist){
            List<SubContentJson> subList = new ArrayList<>();
            tmp.getQuestionJson().setSubContents(subList);
            //单词跟读
            vocabFollowReading(tmp);
            //中译英
            vocabChinaToEnglish(tmp);
            //英译中
            //单词听写  (听音频 , 拼单词
            //单词拼写  (展示 翻译, 拼单词)
        }
    }

    /**
     * 中译英 题目内容
     * @param tmp
     */
    private void vocabChinaToEnglish(QuestionTmp tmp) {
        if(!CollectionUtils.isEmpty(tmp.getVocabList())){
            for(Vocabulary voca:tmp.getVocabList()){
                tmp.getQuestionJson().getSubContents().add(getVocabChinaToEnglishOne(voca, tmp.getVocabList()));
            }
        }
    }

    /**
     * 获取 中译英 内容
     * @param voca
     * @return
     */
    private SubContentJson getVocabChinaToEnglishOne(Vocabulary voca, List<Vocabulary> vocaList) {
        SubContentJson sub = new SubContentJson();
        List<String> trans = parseVocabArray(voca.getTranslationJson());
        sub.setSubContent(CollectionUtils.isEmpty(trans)?"":trans.get(0));//题干内容 为 翻译

        return sub;
    }

    /**
     * 获取 随机
     * @param voca 正确答案
     * @param vocaList 所有 词汇集合
     * @param len 返回集合长度
     * @return
     */
    public List<Vocabulary> getRandomVoca(Vocabulary voca, List<Vocabulary> vocaList, int len){
        List<Vocabulary> resList = new ArrayList<>(len);
        Random random = new Random();
        int answerIndex = random.nextInt(len);//正确答案 序号
        for(int i =0; i<len; i++){
            if(i != answerIndex){
                int listIndex = random.nextInt(vocaList.size());//随机获取 集合中一个元素
                resList.add(vocaList.get(listIndex));
            }else{
                resList.add(voca);
            }
        }
        return resList;
    }

    public static void main(String[] args) {
        Random random = new Random();
        for(int i = 0;i<100;i++){
            System.out.println(random.nextInt(4));
        }
    }



    /**
     * 生成单词跟读相关内容
     * @param tmp
     */
    private void vocabFollowReading(QuestionTmp tmp) {
        //词汇信息不为空
        if(!CollectionUtils.isEmpty(tmp.getVocabList())){
            for(Vocabulary voca:tmp.getVocabList()){
                tmp.getQuestionJson().getSubContents().add(getVocabFollowReadingOne(voca));
            }
        }
    }

    /**
     * 获取 词汇跟读 单个词汇 题目内容
     * @param vocab
     * @return
     */
    public SubContentJson getVocabFollowReadingOne(Vocabulary vocab){
        SubContentJson subContent = new SubContentJson();
        List<String> trans = parseVocabArray(vocab.getTranslationJson());
        String content = "<p>"+vocab.getText()+"</p>".concat(CollectionUtils.isEmpty(trans)?"":("<p>"+trans.get(0)+"</p>"));
        subContent.setSubContent(content);
        /**
         * 口语相关内容
         */
        OralContentJson oral = new OralContentJson();
        oral.setText(vocab.getText());
        oral.setAudioUrl(vocab.getAudioUrl());
        oral.setVoiceText(vocab.getText());
        subContent.setOralContent(oral);
        return subContent;
    }

    /**
     * 解析词汇 内容
     * @param value
     * @return
     */
    public List<String> parseVocabArray(String value){
        if(StringUtils.hasText(value) && !Vocabulary.EMPTY.equals(value)){
            return JSONArray.parseArray(value,String.class);
        }
        return null;
    }

    /**
     * 处理同步练习 练习题目
     * @param tlist
     * @param record
     */
    public boolean syncQuesHandle(List<QuestionTmp> tlist, ImportRecord record){
        /**
         * 题目内容处理
                */
        formatJsonContent(tlist);

        StringBuffer errorBuffer = new StringBuffer();
        tlist.stream().filter(t-> StringUtils.hasText(t.getErrorMsg())).forEach(t->{
            errorBuffer.append(t.getErrorMsg()).append("\n");
        });

        if(errorBuffer.length() != 0){
            //更新 导入记录表 数据
            record.setImportResult(errorBuffer.toString());
            recordService.updateData(record);
            return false;
        }

        //如果没有 错误信息 执行插入操作
        for(QuestionTmp tmp:tlist){
            tmp.setCode(IdWorker.getStringCode());//题目编码
            tmp.setImportCode(record.getCode());
            tmp.setQuestionContent(JSON.toJSONString(tmp.getQuestionJson()));
            tmp.setAnswerJson(JSON.toJSONString(tmp.getAnswerJsonList()));
        }
        return true;
    }

    /**
     * 处理 题目内容
     * @param tlist
     */
    public void formatJsonContent(List<QuestionTmp> tlist) {

        for(QuestionTmp tmp:tlist){
            if(CollectionUtils.isEmpty(tmp.getSubContents())){
                tmp.setErrorMsg("第"+tmp.getLineNum()+"行, 数据有误, 没有子题干内容,");
                continue;
            }
            if(!CollectionUtils.isEmpty(tmp.getSubOptions())){
                //如果 有答案选项 信息 , 那么 选项个数 要和 子题干 个数匹配
                if(tmp.getSubOptions().size() != tmp.getSubContents().size()){
                    tmp.setErrorMsg("第"+tmp.getLineNum()+"行, 数据有误, 选项个数与子题干个数不匹配.");
                    continue;
                }
            }

            if(!CollectionUtils.isEmpty(tmp.getSubAnswers())){
                //如果 有答案 信息 , 那么 答案个数 要和 子题干 个数匹配
                if(tmp.getSubAnswers().size() != tmp.getSubContents().size()){
                    tmp.setErrorMsg("第"+tmp.getLineNum()+"行, 数据有误, 答案个数与子题干个数不匹配.");
                    continue;
                }
            }

            if(!CollectionUtils.isEmpty(tmp.getSubExplains())){
                //如果 有答案选项 信息 , 那么 选项个数 要和 子题干 个数匹配
                if(tmp.getSubExplains().size() != tmp.getSubContents().size()){
                    tmp.setErrorMsg("第"+tmp.getLineNum()+"行, 数据有误, 解析个数与子题干个数不匹配.");
                    continue;
                }
            }
            //该题目json格式对象
            QuestionJson json = tmp.getQuestionJson();
            //json子题目集合对象
            List<SubContentJson> subList = new ArrayList<>();

            json.setSubContents(subList);

            tmp.setQuestionJson(json);

            //子题干内容
            handleSubContents(tmp);

            //题目选项
            handleSubOptions(tmp);

            //答案, 解析
            handleAnswerExplain(tmp);
        }
    }

    /**
     * 处理 答案 & 解析数据
     * @param tmp
     */
    private void handleAnswerExplain(QuestionTmp tmp) {
        /**
         * 问题答案
         */
        if(!CollectionUtils.isEmpty(tmp.getSubAnswers())){
           List<String> answers = tmp.getSubAnswers();

           List<QuesAnswerJson> alist = new ArrayList<>();
           for(int i = 0; i<answers.size(); i++){
               QuesAnswerJson qaj = new QuesAnswerJson();
               String answer = answers.get(i);
               qaj.setIndex(i+1);
               qaj.setAnswer(Arrays.asList(answer.split(",")));
               alist.add(qaj);
           }
           tmp.setAnswerJsonList(alist);
        }
        /**
         * 问题解析
         */
        if(!CollectionUtils.isEmpty(tmp.getSubExplains())){
            //如果有答案的问题
            if(!CollectionUtils.isEmpty(tmp.getAnswerJsonList())){
                List<QuesAnswerJson> alist = tmp.getAnswerJsonList();
                for(int i = 0; i<tmp.getSubExplains().size();i++){
                    alist.get(i).setExplain(tmp.getSubExplains().get(i));
                }
            }else{
                //只有解析没有答案情况
                List<QuesAnswerJson> alist = new ArrayList<>();
                for(int i=0;i<tmp.getSubExplains().size();i++){
                    String explain=tmp.getSubExplains().get(i);
                    QuesAnswerJson qaj = new QuesAnswerJson();
                    qaj.setIndex(i+1);
                    qaj.setExplain(explain);
                    alist.add(qaj);
                }
                tmp.setAnswerJsonList(alist);
            }
        }
    }

    /**
     * 处理子题干
     * @param tmp
     */
    public void handleSubContents(QuestionTmp tmp){
        if(!CollectionUtils.isEmpty(tmp.getSubContents())){
            for(int i = 0;i<tmp.getSubContents().size();i++){
                String subContent = tmp.getSubContents().get(i);
                SubContentJson sub = new SubContentJson();
                sub.setIndex(i+1);
                sub.setSubContent(subContent);
                tmp.getQuestionJson().getSubContents().add(sub);
            }
        }
    }

    /**
     * 处理题目 选项逻辑
     * @param tmp
     */
    public void handleSubOptions(QuestionTmp tmp){
       if(!CollectionUtils.isEmpty(tmp.getSubOptions())){
           List<String> options = tmp.getSubOptions();
           List<SubContentJson> subList = tmp.getQuestionJson().getSubContents();
           for(int i = 0;i<options.size();i++){
               String opLine = options.get(i);//当前选项 数据 A.plays the violin#B.plays baseball#C.has a shower#D.brushes his teeth
               SubContentJson sub = subList.get(i);//当前子题
               List<QuesOptionJson> opList = new ArrayList<>();//当前 子题干 选项集合
               String[] array = opLine.split("#");
               for(int j = 0; j<array.length;j++){
                   String option = array[j];
                   QuesOptionJson qo = new QuesOptionJson();
                   parseOption(option, qo, j);
                   opList.add(qo);
               }
               sub.setOptions(opList);
           }
       }
    }

    /**
     * 解析  一个选项内容
     * A.plays the violin
     * @param option
     * @param qo
     */
    public void parseOption(String option, QuesOptionJson qo, int index){
       if(option.startsWith(PREFIX_A) || option.startsWith(PREFIX_B)
               || option.startsWith(PREFIX_C)|| option.startsWith(PREFIX_D)
               || option.startsWith(PREFIX_E)|| option.startsWith(PREFIX_F)
               || option.startsWith(PREFIX_G)|| option.startsWith(PREFIX_H)
               || option.startsWith(PREFIX_I)){
           String text = option.substring(2, option.length());
           qo.setText(text.trim());

           String value = option.substring(0, 1);

           qo.setShowValue(value);
           qo.setValue(value);
           qo.setIndex(index+1);
       }else{
           qo.setText(option);
           qo.setValue(option);
           qo.setIndex(index+1);
       }
    }

    /**
     * 处理词汇内容
     * @param tlist
     */
    public void handleVocabulary(List<QuestionTmp> tlist){
       List<String> vocabs = new ArrayList<>();
       for(QuestionTmp tmp:tlist){
           if(!CollectionUtils.isEmpty(tmp.getVocabularies())){
               for(String vocab:tmp.getVocabularies()){
                   if(!vocabs.contains(vocab)){
                       vocabs.add(vocab);
                   }
               }
           }
       }
       Map<String,Object> map = new HashMap<>();
       map.put("wordList", vocabs);
       List<Vocabulary> vlist = vocabularyService.findByBiz(map);
       for(QuestionTmp tmp:tlist){
           if(!CollectionUtils.isEmpty(tmp.getVocabularies())){
               tmp.setVocabList(vlist.stream().filter(v-> tmp.getVocabularies().contains(v.getText())).collect(Collectors.toList()));
           }
       }
    }


    /**
     * 处理 题目所属课本 单元 以及 关联知识点
     * @param tmpList
     */
    public void handleBookUnitKPs(List<QuestionTmp> tmpList){
       List<String> books = new ArrayList<>();//课本
       List<String> kps = new ArrayList<>();//知识点
        for(QuestionTmp t:tmpList){
            if(!books.contains(t.getMaterialBook())){
                books.add(t.getMaterialBook());
            }
            if(!CollectionUtils.isEmpty(t.getKnowledgePoints())){
                for(String kp:t.getKnowledgePoints()){
                    if(!kps.contains(kp)){
                        kps.add(kp);
                    }
                }
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("bookNames", books);
        List<Book> bookList = bookService.getBookListWithUnit(map);
        //查询知识点
        map.clear();
        map.put("kpNames", kps);
        List<KnowledgePoint> kpList = knowledgePointService.findByBiz(map);

        //赋值 课本单元编码, 知识点编码
        for(QuestionTmp tmp:tmpList){
            //找到匹配的课本
            Book book = bookList.stream().filter(b-> b.getName().equals(tmp.getMaterialBook())).findFirst().get();
            //匹配 单元信息
            BookUnit unit = book.getUnitList().stream().filter(u-> u.getName().equals(tmp.getBookUnit())).findFirst().get();
            if(null != unit){
                //设置 关联 课本单元
                tmp.setBookCodes(unit.getBookCode().concat(",").concat(unit.getCode()));
            }
            if(!CollectionUtils.isEmpty(tmp.getKnowledgePoints())){
                StringBuffer sbCode = new StringBuffer();
                StringBuffer sbName = new StringBuffer();
                for(KnowledgePoint kp:kpList){
                    if(tmp.getKnowledgePoints().contains(kp.getName())){
                        sbCode.append(kp.getLongCode()).append(",");
                        sbName.append(kp.getName()).append(",");
                    }
                }
                if(sbCode.length()>0){
                    //设置 知识点 & 知识点标签
                    tmp.setKpCodes(sbCode.substring(0,sbCode.length()-1));
                    tmp.setLabelName(sbName.substring(0,sbName.length()-1));
                }
            }
        }

    }

    /**
     * 解析上传的 excel数据
     * @param filePath
     */
    public List<QuestionTmp> parseExcelData(String filePath, QuesType type){
        List<String[]> list = ExcelReader.getExcelData(new File(filePath));
        Map<Integer,String> map = new HashMap<>();
        for(int i=0; i<list.get(0).length;i++){
            String key = list.get(0)[i];
            if(StringUtils.hasText(key)){
                map.put(i, key);
            }
        }
        List<QuestionTmp> tmpList = new ArrayList<>();
        for(int i = 1; i<list.size(); i++){
            tmpList.add(parseQuestionOne(list.get(i), map, type, i));
        }
        return tmpList;
    }

    /**
     * 解析一行数据
     * @param data
     * @param map
     * @return
     */
    public QuestionTmp parseQuestionOne(String[] data, Map<Integer,String> map, QuesType type, int line){
        QuestionTmp tmp = new QuestionTmp();
        //设置题型 相关信息
        tmp.setQuesTypeCode(type.getLongCode());
        tmp.setQuesType(type.getQuesType());
        tmp.setQuesSubType(type.getQuesSubType());
        tmp.setQuesTypeName(type.getName());
        tmp.setLineNum(line+2);//excel行号 + 2
        tmp.setCreateDate(new Date());

        QuestionJson json = new QuestionJson();
        for(int i=0; i<data.length; i++){
           String field = map.get(i);//获取 当前列 标识 字符
           String value = data[i];
           putQuestionVal(field, value, tmp, json);
        }
        tmp.setQuestionJson(json);
        return tmp;
    }

    /**
     * 根据列 标识符 对 题目对象赋值
     * @param field
     * @param value
     */
    public void putQuestionVal(String field, String value, QuestionTmp tmp, QuestionJson json){
       if(ExcelColumnEnum.knowledgePoints.toString().equals(field)){
           //处理知识点
           if(StringUtils.hasText(value)){
               tmp.setKnowledgePoints(SpecialCharUtils.matchExcelData(value));//先直接设置 汇总到list集合后 统一查询 赋 编码值
           }
       }else if(ExcelColumnEnum.difficultyInt.toString().equals(field)){
           //难易程度
           if(StringUtils.hasText(value)){
               tmp.setDegree(String.valueOf(Double.valueOf(value).intValue()));
           }
       }else if(ExcelColumnEnum.materialBook.toString().equals(field)){
           //教材
           if(StringUtils.hasText(value)){
               tmp.setMaterialBook(value);
           }
       }else if(ExcelColumnEnum.bookUnit.toString().equals(field)){
           //单元
           if(StringUtils.hasText(value)){
               tmp.setBookUnit(value);
           }
       }else if(ExcelColumnEnum.description.toString().equals(field)){
           //题目描述
           if(StringUtils.hasText(value)){
               json.setDescription(value);
           }
       }else if(ExcelColumnEnum.audioContent.toString().equals(field)){
           if(StringUtils.hasText(value)){
               json.setAudioContent(value);
           }
       }else if(ExcelColumnEnum.content.toString().equals(field)){
           if(StringUtils.hasText(value)){
               json.setContent(value);
           }
       }else if(ExcelColumnEnum.imgContent.toString().equals(field)){
           if(StringUtils.hasText(value)){
               json.setImgContent(value);
           }
       }else if(ExcelColumnEnum.title.toString().equals(field)){
           if(StringUtils.hasText(value)){
               json.setTitle(value);
           }
       }else if(ExcelColumnEnum.vocabulary.toString().equals(field)){
           //词汇信息 , 等等 要查数据库 获取 音频 音标等信息
           if(StringUtils.hasText(value)){

               tmp.setVocabularies(Arrays.asList(value.split(",")));
           }
       }else if(ExcelColumnEnum.subContent.toString().equals(field)){
           if(StringUtils.hasText(value)){
               tmp.setSubContents(SpecialCharUtils.matchExcelData(value));
           }
       }else if(ExcelColumnEnum.subAnswers.toString().equals(field)){
           if(StringUtils.hasText(value)){
               tmp.setSubAnswers(SpecialCharUtils.matchExcelData(value));
           }
       }else if(ExcelColumnEnum.subOptions.toString().equals(field)){
           if(StringUtils.hasText(value)){
               tmp.setSubOptions(SpecialCharUtils.matchExcelData(value));
           }
       }else if(ExcelColumnEnum.subExplains.toString().equals(field)){
           if(StringUtils.hasText(value)){
               tmp.setSubExplains(SpecialCharUtils.matchExcelData(value));
           }
       }else if(ExcelColumnEnum.expectTime.toString().equals(field)){
           if(StringUtils.hasText(value)){
               tmp.setExpectTimes(Double.valueOf(value).intValue());
           }
       }
    }
}